iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
Modern Web

從0開始的的Angular站台架設-Stnadalone 系列 第 21

D20 Angular Router(下) Params、Auth Guard

  • 分享至 

  • xImage
  •  

昨天我們說了基礎的Router的設置,今天我們來說說要怎麼把params放入到我們的網址中並且去取用他,另外就是如何進行Auth Guard(路由守衛)

首先先講講Params的應用吧


我們在進行電商的購物流程之中,一定會有個經歷就是分享我們自己喜歡的商品給他人的時後,網址上的params總是掛了一堆東西

其實這個行為也是緊貼於業務行為邏輯的

當消費者要分享他的屬意商品的時候我們要怎麼在最快的狀況之下從Serve中拿回我們需要顯示的資料?以及如何最快拿出我們存在 store 之中的資料?

我們可以很簡單的用一個商品編號來進行SQL的檢索沒有錯,但是流量成長起來之後頻繁的去敲DB似乎不是一個好主意,那怕我們將其儲存在Storeage之中做快取

這時候前端系統在User與Serve之中所要做的事項就是要盡可能的先跟後端拿取一些基礎的系統參數,商品分類、行銷活動分類、外部行銷活動分類、使用者資訊...等等,然後放入localStorage中進行儲存-以前可能會這樣做啦,但現在會優先放入到store 之中進行緩存,畢竟放在外面還是有給其他人竄改的機會,並且我們現在有selector進行緩存的狀況之下,我們可以盡可能的保留瀏覽器記憶體的空間

所以param對於我來說是一個可以盡快進行載入當前資訊的方法,相當於醫生跟我縮藥品編號,我低頭就直接在桌上常用藥品櫃中迅速配好藥包給需求者

實作上也很簡單,主要有分兩種,一種是在element上直接綁param,觸發路由轉移事件時立即將其掛載上url之上,另一種則是透過component中用Method進行跳轉,那麼我們就先講講掛載在element上的方法

掛載的主體釋例我用Header來進行實作,而實作的路由主體component我則是將其命名為shoppingListComponent,本身資料的載入應該是透過param來進行不同的分類切換,而非用shoppingCategory來進行不同分類的載入,這也是比較偏向於UX的情境分析

<div class="header py-4 text-primary-white">
  <div class="header-lv1 w-full mb-default flex items-center justify-between">
    ...
  </div>
  <div class="header-lv2 w-full mb-default flex items-center justify-center">
    ...
  </div>
  <div class="header-lv3 w-full">
    <swiper [config]="config">
      <ng-template swiperSlide *ngFor="let categoryItem of categories"
        ><button
          type="button"
          [routerLink]="['/eShopping/ShoppingList']"
          [queryParams]="{ category: categoryItem['categoryID'] }"
        >
          {{ categoryItem.categoryName }}
        </button></ng-template
      >
    </swiper>
  </div>
</div>

掛載的過程其實也很簡單,只要將routerLink添加上我們要載入的路由座導向,並使用queryParams加上我們需要掛載的參數

在進行載入的HeaderComponent我們也需要進行RouteModule的載入才能讓他正常運行,然後因為Header是為了用Swiper所以有做過局部還原,我們在這邊需要進行引用的是HeaderModule

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeaderComponent } from './header.component';
import { SwiperModule } from 'swiper/angular';
import { RouterModule } from '@angular/router';
@NgModule({
  declarations: [HeaderComponent],
  imports: [CommonModule, SwiperModule, RouterModule],
  exports: [HeaderComponent],
})
export class HeaderModule {}

接下來則是如何從url摳下來我們所需要的參數

import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute } from '@angular/router';

@Component({
  standalone: true,
  imports: [CommonModule],
  templateUrl: './shopping-list.component.html',
  styleUrls: ['./shopping-list.component.scss'],
})
export class ShoppingListComponent implements OnInit {
  private activatedRoute = inject(ActivatedRoute);
  ngOnInit(): void {
    this.activatedRoute.queryParams.subscribe((res) => {
      console.log(res);
    });
  }
}

透過ActivatedRoutequeryParams我們就可以輕而易舉的將我們的參數拿下來進行使用了

接下來我們來說說透過Method進行param的掛載

  private router = inject(Router);
  ...
  goToCategory(categoryID: number): void {
    this.router.navigate(['/eShopping/ShoppingList'], { queryParams: { category: categoryID } });
  }

其實我們也就需要將原本放在element之中的屬性用Router去做添加即可

queryParams假如有不同component有各自的param要進行掛載的話呢?自家有自家的分類params,我要進行消費者行為tracking的話,總不能每次都拿下一整段url然後在後面掛載導入吧?

這時候我們可以用queryParamsHandling來進行merge,在切換路由的時候掛載的queryparams就能被保留下來,這個方法可以很好的協助我們將一些使用者操作情境掛在url上做GA分析

簡單的說完了router與activatedRoute的queryParams動作,接下來我們來說說Auth Gard


AuthGard在Angular的層級之中,使屬於Application的層級,高於Route的Module的層級,換言之一旦AuthGard沒有過的話,下轄的所有路由連渲染都不會進行渲染

這邊我們先留個念想,先來講講要怎麼進行實作

他其實在Route進行Method的引用canActivateChild即可

import { Routes } from '@angular/router';
import { IndexLayoutComponent } from '../../shared/templates/index-layout/index-layout.component';
import { StoreManagementGuard } from './guards/auth.guard';

export const routes: Routes = [
  {
    path: 'eShopping',
    canActivateChild: [StoreManagementGuard],// <--這裡
    component: IndexLayoutComponent,
    loadChildren: () => import('../../feature/e-shopping/e-shopping.routes'),
  },
  {
    path: '**',
    redirectTo: '/eShopping/Home',
    pathMatch: 'full',
  },
];

而guards我本身會放在Core之中進行管理,那怕在不同的子路由之中我都可以進行路由守衛的任務,但它的應用實作依舊是App僅讀取一次後續不斷的做更新而已

core/
|    |-routes
|    |    |-guards
|    |    |    |-auth.guard.ts

實作的程式也不難,示例如下

import { CanActivateChildFn, Router } from '@angular/router';
import { inject } from '@angular/core';

export const StoreManagementGuard: CanActivateChildFn = (route, state) => {
  const router = inject(Router);
  if (authenticationService.isStore()) {
    return true;
  }
  return router.parseUrl('/Home');
};

透過canActivateChild的實作,我們可以發現他能接受兩種不同type的回傳值,當我值為true的時候便能進入到子路由之中,而當我導入一個路由的時候他也會將其實作導入至其目的地中,值為false的話你不論發起多少次請求,也倒不過去,硬是用url倒過去的話也會被倒回自己預設的萬用路由接口或是errorPage

接下來戲肉來了,既然他可以吃我回傳值進行Method的執行的話?那我是不是可以進行一個Observe來做非同步驗證呢?
理論上可行,實作上可行但我不建議

首先我會建議透過sessionstore兩者進行雙重路由守衛的驗證與管理,不論是JWT的實作或是permisson的限制,都是透過瀏覽器儲存session作為重整依據,store作為系統參數與敏感訊息的暫存區,反正我們也可以透過queryparams來得到我們所需要的資訊

這麼做的最主要原因是預防async非同步回來的有Timeout的風險,可別忘了他的監管範圍是下轄所有路由,一旦漏接一次就會直接被彈出去到非權限操作情境,對於使用者操作體驗可不是很優質的感受,後續要管理user story也會變的很麻煩
以上Route的內容差不多就這樣了,謝謝大家花時間來看

明天我們將會進行Library的安裝與電子商務基礎layout的實作


上一篇
D19 Angular Router(上) Route基礎、/:id動態路由
下一篇
D21 Component套件庫Prime的RWD應用
系列文
從0開始的的Angular站台架設-Stnadalone 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言